#!/usr/bin/env python3
import os
import json
import subprocess
import sys

def load_vulnerability_record(json_file):
    """从 JSON 文件中加载漏洞记录"""
    with open(json_file, "r", encoding="utf-8") as f:
        data = json.load(f)
    return data

def derive_repo_url(html_url):
    """
    根据漏洞记录中的 html_url 推导出仓库的克隆地址。
    例如：
      输入: https://github.com/mono/mono/commit/89d1455a80ef13cddee5d79ec00c06055da3085c
      输出: https://github.com/mono/mono.git
    """
    parts = html_url.split("/")
    if "commit" in parts:
        idx = parts.index("commit")
        repo_parts = parts[:idx]  # 提取仓库部分
        repo_url = "/".join(repo_parts) + ".git"
        return repo_url
    return html_url

def generate_clone_dir(repo_url):
    """
    根据仓库 URL 自动生成本地克隆目录名称。
    例如：
      输入: https://github.com/mono/mono.git
      输出: ./mono_repo
    """
    parts = repo_url.split("/")
    repo_name = parts[-1]
    if repo_name.endswith(".git"):
        repo_name = repo_name[:-4]
    clone_dir = f"./{repo_name}_repo"
    return clone_dir

def clone_repo(repo_url, clone_dir):
    """如果本地不存在仓库，则克隆仓库"""
    if not os.path.exists(clone_dir):
        print(f"正在从 {repo_url} 克隆仓库到 {clone_dir}...")
        subprocess.run(["git", "clone", repo_url, clone_dir], check=True)
    else:
        print(f"仓库已存在于 {clone_dir}.")

def checkout_commit(repo_dir, commit_id):
    """检出指定 commit"""
    print(f"切换到 commit {commit_id} ...")
    subprocess.run(["git", "checkout", commit_id], cwd=repo_dir, check=True)

def get_parent_commit(repo_dir, commit_id):
    """获取指定 commit 的父提交，作为漏洞存在时的版本"""
    result = subprocess.run(
        ["git", "rev-parse", f"{commit_id}^"],
        cwd=repo_dir,
        capture_output=True,
        text=True,
        check=True
    )
    parent_commit = result.stdout.strip()
    return parent_commit

def get_diff(repo_dir, commit_a, commit_b):
    """获取两个 commit 之间的差异"""
    result = subprocess.run(
        ["git", "diff", commit_a, commit_b],
        cwd=repo_dir,
        capture_output=True,
        text=True,
        check=True
    )
    return result.stdout

def main():
    if len(sys.argv) < 2:
        print("用法: python script.py <vulnerability_record_dir>")
        sys.exit(1)
    
    # 从指定目录中依次读取该目录下的文件
    directory = sys.argv[1]
    for filename in os.listdir(directory):
        if filename.endswith(".json"):
            json_file = os.path.join(directory, filename)
            print(f"处理文件: {json_file}")
            
            record = load_vulnerability_record(json_file)
            
            # 从漏洞记录中提取所需信息
            fix_commit = record.get("commit_id")
            html_url = record.get("html_url")
            if not fix_commit or not html_url:
                print("JSON 文件中缺少 commit_id 或 html_url 字段。")
                sys.exit(1)
            
            # 自动生成仓库克隆地址和本地目录
            repo_url = derive_repo_url(html_url)
            clone_dir = os.path.join(os.path.dirname(directory), "ReposVul_code", generate_clone_dir(repo_url))
            
            print(f"自动解析信息：\n仓库地址: {repo_url}\n修复提交: {fix_commit}\n本地目录: {clone_dir}\n")
            
            # 克隆仓库
            clone_repo(repo_url, clone_dir)
            
            # 检出修复提交版本
            checkout_commit(clone_dir, fix_commit)
            
            # 获取修复前版本（父提交）
            before_commit = get_parent_commit(clone_dir, fix_commit)
            print(f"修复前版本（父提交）: {before_commit}")
            
            # 获取修复前后代码差异
            diff_output = get_diff(clone_dir, before_commit, fix_commit)
            print("修复前后代码差异：")
            print(diff_output)

    

if __name__ == "__main__":
    main()
